/*================================================================
*   
*   文件名称：sand.h
*   创 建 者：yq
*   创建日期：2023年02月26日
*   描    述：倒沙我最强
*
================================================================*/

#ifndef SAND_H
#define SAND_H

#include <vector>
#include <iostream>
#include <string>

namespace yq {

class sand {
	enum { capacity = 4 , emptybottle = 2};
	typedef std::vector<int> bottle;

private:
	// 瓶子总数
	int _cnt;
	// bottles 
	bottle* bottles;
	// end
	bool _finish;

	// 步骤
	std::vector<std::pair<int,int>> steps;
	
public:
	sand(int size): _cnt(size) {
	  bottles = (new bottle[_cnt]);
		_finish = false;
	}
	~sand() {
		delete [] bottles;
	}

	// input
	void input() {
		auto str1 = "请输入第" ;
		auto str2 = "瓶的状态\n";
		std::string in;
		
		for (int i = 0; i < _cnt - emptybottle; ++ i) {
			std::cout << str1 << i + 1 << str2 ;
			std::cin >> in;
			
			if (in.size() != capacity) {
				std::cout << "error please input again!\n" ;
				-- i;
				continue;
			}
			
			std::cout << in << std::endl;
			std::reverse(in.begin(), in.end());
			for (auto c: in) {
				bottles[i].push_back(c);
			}
		}

		// debug
		// std::cout << "input is ok \n";
		
	}

	// opera
	void opera() {
		_finish = isok();
		if (_finish) return ;

		bottle* p = new bottle[_cnt];
		for (int i = 0; i < _cnt; ++ i) {
			p[i] = bottles[i];
		}

		for (int i = 0; i < _cnt; ++ i) {
			for (int j = 0; j < _cnt; ++ j) {
				if (i == j) continue;
				// bool jg = judge(bottles[i], bottles[j]);
				// std::cout << jg << '\n' ;
				if (judge(bottles[i], bottles[j])) {
					// std::cout << "op " << i << j << std::endl;
					pour(i, j);
					// show();
					steps.push_back(std::make_pair(i, j));
					opera();
					if (_finish) {
					 	delete[] p;
						return ;
					}
					steps.pop_back();
					for (int k = 0; k < _cnt; ++ k) {
						bottles[k] = p[k];
					}
				}
			}	// for j
		}	// for i
			
		delete[] p;
	}

	void show() {
		for (int i = 0; i < _cnt; ++ i) {
			for (auto c: bottles[i]) std::cout << (char)c ;
			std::cout << "\n";
		}
		std::cout << "\n";
	}


	// show result
	void show_ans() {
		for (auto& [a, b]: steps) {
			std::cout << a + 1 << "  ->  " << b + 1 << "\n" ;
		}
	}
				

	// 判断是否能倒a -> b
	bool judge(const bottle& a, const bottle& b) {
		
		if (b.size() == capacity || a.empty()) return false;
		if (!b.empty() && a.back() != b.back()) return false;

		// a 中相同的数量
		int cnt = 1;
		int top = a.back();
		for (int i = a.size() - 1; i --; ) {
			if (top == a[i]) cnt ++;
			else break;
		}
		if (b.size() + cnt > capacity) return false;
		if (b.empty() && cnt == a.size()) return false;
		
		return true;
	}

	// 倾倒
	void pour(int a, int b) {
		
		int top = bottles[a].back();
		for (int i = bottles[a].size(); i --; ) {
			if (top == bottles[a].back()) {
				bottles[a].pop_back();
				bottles[b].push_back(top);
			} else { 
				break;
			}
		}

		return ;
	}

	// isok
	bool isok() {
		if (_finish) return true;
		for (int i = 0; i < _cnt; ++ i) {
			if (bottles[i].empty()) continue;
			if (bottles[i].size() != capacity) return false;
			int top = bottles[i].back();
			for (auto s: bottles[i]) 
				if (top != s) return false;
		}
		return true;
	}

	

	
};	// class sand

} // namespace yq


#endif	// #ifndef SAND_H
